Forward proxy initialize as bridge behavior#4228
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5830c1d117
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| _create_client_factory, | ||
| ) | ||
|
|
||
| settings.setdefault("forward_initialize", True) |
There was a problem hiding this comment.
Stop forwarding initialize by default in create_proxy
create_proxy() now unconditionally enables forward_initialize, so a proxy handshake always opens and initializes the upstream client before responding locally. This reintroduces the eager remote availability/auth check that this change is trying to remove, and it means default proxies still fail at Client(proxy) time whenever the upstream is down instead of deferring failures to the first proxied operation. That breaks lazy/degraded startup scenarios and keeps the same side effects (extra upstream sessions/auth) on every initialize.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 23b797286d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| self.add_provider(provider) | ||
| if validate_on_initialize: | ||
| self.middleware.append(ProxyInitializeMiddleware(self)) | ||
| self.middleware.append(ProxyInitializeMiddleware(self)) |
There was a problem hiding this comment.
Restore opt-out for initialize forwarding in FastMCPProxy
This change makes FastMCPProxy always install ProxyInitializeMiddleware, so every downstream initialize now forces an upstream connect/initialize handshake with no way to disable it. That regresses the prior lazy behavior for direct FastMCPProxy(...) usage (and any caller that previously used validate_on_initialize=False), causing startup to fail immediately when upstream is temporarily unavailable instead of deferring failure to the first proxied operation; this is especially disruptive for stateful/custom client_factory mounting flows that rely on lazy or degraded startup.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9b4598fe91
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if "roots" in self._proxy_restoring_handler_keys: | ||
| self._session_kwargs["list_roots_callback"] = create_roots_callback( | ||
| _make_restoring_handler(default_proxy_roots_handler, self._proxy_rc_ref) | ||
| ) |
There was a problem hiding this comment.
Preserve overridden callbacks when cloning stateful proxy clients
StatefulProxyClient.new() now calls _bind_restoring_handlers(), which unconditionally rewrites callbacks for any handler key that was defaulted at construction time. That means a caller who later customizes behavior (for example via set_roots, set_sampling_callback, or set_elicitation_callback) will have those overrides silently discarded on new_stateful() clones, and the proxy falls back to the built-in forwarding handlers instead. This is a regression from prior behavior where Client.new() preserved post-init callback updates, and it can break custom routing/auth/context logic in stateful proxy deployments.
Useful? React with 👍 / 👎.
FastMCP proxies are lazy bridges: they do not touch the upstream server during Python construction or process startup, but they do forward real downstream MCP requests.
initializeis part of that protocol surface, so a proxy only reports successful initialization after the upstream server initializes successfully too.This removes the
validate_on_initializeconcept and makes initialize forwarding inherent toFastMCPProxy. A bogus URL, denied upstream auth, or non-MCP upstream now fails the downstream initialize handshake instead of producing a local “connected” proxy with empty or failed capability fetches.The proxy still does no upstream work until a client connects and sends
initialize. Existing HTTP/SSE authorization header forwarding remains in the transport path, andfastmcp-remotecontinues to use strict provider errors so later proxied fetches surface upstream failures instead of empty results.